#include "os.h"
#include "fileio.h"
#include "log.h"
#include "ojData.h"
#include <iostream>
#include <string>
#include <time.h>
#include <fstream>
using namespace std;

inline ProcessSTDNO switchStdno(const ProcessSTDNO &pstdno)
{
    ProcessSTDNO tmp(STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
    if (pstdno.in >= 0) {
        tmp.in = dup(STDIN_FILENO);
        dup2(pstdno.in, STDIN_FILENO);
    }
    if (pstdno.out >= 0) {
        tmp.out = dup(STDOUT_FILENO);
        dup2(pstdno.out, STDOUT_FILENO);
    }
    if (pstdno.err >= 0) {
        tmp.err = dup(STDERR_FILENO);
        dup2(pstdno.err, STDERR_FILENO);
    }
    return tmp;
}

inline void closeStdno(const ProcessSTDNO &pstdno)
{
    if (pstdno.in >= 0) {
        close(pstdno.in);
    }
    if (pstdno.out >= 0) {
        close(pstdno.out);
    }
    if (pstdno.err >= 0) {
        close(pstdno.err);
    }
}

inline ProcessSTDNO stdnoFromSTD(const ProcessSTD &pstd)
{
    ProcessSTDNO pstdno;
    int ret;
    if (pstd.in != "") {
        ret = open(pstd.in.c_str(), pstd.inmod);
        if (ret < 0) {
            Log::instance().getError() << "open " << pstd.in << " error" << endl;
            _exit(1);
        }
        pstdno.in = ret;
    }
    if (pstd.out != "") {
        ret = open(pstd.out.c_str(), pstd.outmod);
        if (ret < 0) {
            Log::instance().getError() << "open " << pstd.out << " error" << endl;
            _exit(1);
        }
        pstdno.out = ret;
    }
    if (pstd.err != "") {
        ret = open(pstd.err.c_str(), pstd.errmod);
        if (ret < 0) {
            Log::instance().getError() << "open " << pstd.err << " error" << endl;
            _exit(1);
        }
        pstdno.err = ret;
    }
    return pstdno;
}

std::string getLocalTimeStr()
{
    char str[50];
    time_t now = time(NULL);
    strftime(str, 50, "%x %X", localtime(&now));
    return string(str);
}

void printTimeSpanToOutAndError()
{
    string nowTime = getLocalTimeStr();
    Log::instance().getError() << nowTime << "-----------------" << endl;
    Log::instance().getOutput() << nowTime << "-----------------" << endl;
}

void printTimeSpanToOut()
{
    string nowTime = getLocalTimeStr();
    Log::instance().getOutput() << nowTime << "-----------------" << endl;
}

void printTimeSpanToError()
{
    string nowTime = getLocalTimeStr();
    Log::instance().getError() << nowTime << "-----------------" << endl;
}

#ifdef __linux__
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>    /* For struct user_regs_sturct */
#include <sys/syscall.h> /* For SYS_write etc */
#include <sys/reg.h>     /* For constants ORI_EAX etc */
#include <sys/resource.h>
#include <sys/ptrace.h>
#include <linux/ptrace.h>
#include <linux/seccomp.h>
#include <seccomp.h>
#include <signal.h>
#include <stdio.h> /*for stdio*/
#include <sys/time.h>
#include <pwd.h>



const std::vector<seccomp_ruler> base_seccomp_rules = {
    generate_seccomp_ruler(__NR_getcwd),
    generate_seccomp_ruler(__NR_chdir),
    generate_seccomp_ruler(__NR_fchdir),
    generate_seccomp_ruler(__NR_rename),
    generate_seccomp_ruler(__NR_mkdir),
    generate_seccomp_ruler(__NR_rmdir),
    generate_seccomp_ruler(__NR_creat),
    generate_seccomp_ruler(__NR_link),
    generate_seccomp_ruler(__NR_unlink),
    generate_seccomp_ruler(__NR_symlink),
    generate_seccomp_ruler(__NR_readlink),
    generate_seccomp_ruler(__NR_chmod),
    generate_seccomp_ruler(__NR_fchmod),
    generate_seccomp_ruler(__NR_chown),
    generate_seccomp_ruler(__NR_fchown),
    generate_seccomp_ruler(__NR_lchown),
    generate_seccomp_ruler(__NR_umask),
    generate_seccomp_ruler(__NR_gettimeofday),
    generate_seccomp_ruler(__NR_getrlimit),
    generate_seccomp_ruler(__NR_getrusage),
    generate_seccomp_ruler(__NR_sysinfo),
    generate_seccomp_ruler(__NR_times),
    generate_seccomp_ruler(__NR_ptrace),
    generate_seccomp_ruler(__NR_getuid),
    generate_seccomp_ruler(__NR_syslog),
    generate_seccomp_ruler(__NR_getgid),
    generate_seccomp_ruler(__NR_setuid),
    generate_seccomp_ruler(__NR_setgid),
    generate_seccomp_ruler(__NR_geteuid),
    generate_seccomp_ruler(__NR_getegid),
    generate_seccomp_ruler(__NR_setpgid),
    generate_seccomp_ruler(__NR_getppid),
    generate_seccomp_ruler(__NR_getpgrp),
    generate_seccomp_ruler(__NR_setsid),
    generate_seccomp_ruler(__NR_setreuid),
    generate_seccomp_ruler(__NR_setregid),
    generate_seccomp_ruler(__NR_getgroups),
    generate_seccomp_ruler(__NR_setgroups),
    generate_seccomp_ruler(__NR_setresuid),
    generate_seccomp_ruler(__NR_getresuid),
    generate_seccomp_ruler(__NR_setresgid),
    generate_seccomp_ruler(__NR_getresgid),
    generate_seccomp_ruler(__NR_getpgid),
    generate_seccomp_ruler(__NR_setfsuid),
    generate_seccomp_ruler(__NR_setfsgid),
    generate_seccomp_ruler(__NR_getsid),
};

const char *const sysCallList[] =
{
"__NR_read","__NR_write","__NR_open","__NR_close","__NR_stat","__NR_fstat","__NR_lstat","__NR_poll","__NR_lseek","__NR_mmap","__NR_mprotect","__NR_munmap","__NR_brk","__NR_rt_sigaction","__NR_rt_sigprocmask","__NR_rt_sigreturn","__NR_ioctl","__NR_pread64","__NR_pwrite64","__NR_readv","__NR_writev","__NR_access","__NR_pipe","__NR_select","__NR_sched_yield","__NR_mremap","__NR_msync","__NR_mincore","__NR_madvise","__NR_shmget","__NR_shmat","__NR_shmctl","__NR_dup","__NR_dup2","__NR_pause","__NR_nanosleep","__NR_getitimer","__NR_alarm","__NR_setitimer","__NR_getpid","__NR_sendfile","__NR_socket","__NR_connect","__NR_accept","__NR_sendto","__NR_recvfrom","__NR_sendmsg","__NR_recvmsg","__NR_shutdown","__NR_bind","__NR_listen","__NR_getsockname","__NR_getpeername","__NR_socketpair","__NR_setsockopt","__NR_getsockopt","__NR_clone","__NR_fork","__NR_vfork","__NR_execve","__NR_exit","__NR_wait4","__NR_kill","__NR_uname","__NR_semget","__NR_semop","__NR_semctl","__NR_shmdt","__NR_msgget","__NR_msgsnd","__NR_msgrcv","__NR_msgctl","__NR_fcntl","__NR_flock","__NR_fsync","__NR_fdatasync","__NR_truncate","__NR_ftruncate","__NR_getdents","__NR_getcwd","__NR_chdir","__NR_fchdir","__NR_rename","__NR_mkdir","__NR_rmdir","__NR_creat","__NR_link","__NR_unlink","__NR_symlink","__NR_readlink","__NR_chmod","__NR_fchmod","__NR_chown","__NR_fchown","__NR_lchown","__NR_umask","__NR_gettimeofday","__NR_getrlimit","__NR_getrusage","__NR_sysinfo","__NR_times","__NR_ptrace","__NR_getuid","__NR_syslog","__NR_getgid","__NR_setuid","__NR_setgid","__NR_geteuid","__NR_getegid","__NR_setpgid","__NR_getppid","__NR_getpgrp","__NR_setsid","__NR_setreuid","__NR_setregid","__NR_getgroups","__NR_setgroups","__NR_setresuid","__NR_getresuid","__NR_setresgid","__NR_getresgid","__NR_getpgid","__NR_setfsuid","__NR_setfsgid","__NR_getsid","__NR_capget","__NR_capset","__NR_rt_sigpending","__NR_rt_sigtimedwait","__NR_rt_sigqueueinfo","__NR_rt_sigsuspend","__NR_sigaltstack","__NR_utime","__NR_mknod","__NR_uselib","__NR_personality","__NR_ustat","__NR_statfs","__NR_fstatfs","__NR_sysfs","__NR_getpriority","__NR_setpriority","__NR_sched_setparam","__NR_sched_getparam","__NR_sched_setscheduler","__NR_sched_getscheduler","__NR_sched_get_priority_max","__NR_sched_get_priority_min","__NR_sched_rr_get_interval","__NR_mlock","__NR_munlock","__NR_mlockall","__NR_munlockall","__NR_vhangup","__NR_modify_ldt","__NR_pivot_root","__NR__sysctl","__NR_prctl","__NR_arch_prctl","__NR_adjtimex","__NR_setrlimit","__NR_chroot","__NR_sync","__NR_acct","__NR_settimeofday","__NR_mount","__NR_umount2","__NR_swapon","__NR_swapoff","__NR_reboot","__NR_sethostname","__NR_setdomainname","__NR_iopl","__NR_ioperm","__NR_create_module","__NR_init_module","__NR_delete_module","__NR_get_kernel_syms","__NR_query_module","__NR_quotactl","__NR_nfsservctl","__NR_getpmsg","__NR_putpmsg","__NR_afs_syscall","__NR_tuxcall","__NR_security","__NR_gettid","__NR_readahead","__NR_setxattr","__NR_lsetxattr","__NR_fsetxattr","__NR_getxattr","__NR_lgetxattr","__NR_fgetxattr","__NR_listxattr","__NR_llistxattr","__NR_flistxattr","__NR_removexattr","__NR_lremovexattr","__NR_fremovexattr","__NR_tkill","__NR_time","__NR_futex","__NR_sched_setaffinity","__NR_sched_getaffinity","__NR_set_thread_area","__NR_io_setup","__NR_io_destroy","__NR_io_getevents","__NR_io_submit","__NR_io_cancel","__NR_get_thread_area","__NR_lookup_dcookie","__NR_epoll_create","__NR_epoll_ctl_old","__NR_epoll_wait_old","__NR_remap_file_pages","__NR_getdents64","__NR_set_tid_address","__NR_restart_syscall","__NR_semtimedop","__NR_fadvise64","__NR_timer_create","__NR_timer_settime","__NR_timer_gettime","__NR_timer_getoverrun","__NR_timer_delete","__NR_clock_settime","__NR_clock_gettime","__NR_clock_getres","__NR_clock_nanosleep","__NR_exit_group","__NR_epoll_wait","__NR_epoll_ctl","__NR_tgkill","__NR_utimes","__NR_vserver","__NR_mbind","__NR_set_mempolicy","__NR_get_mempolicy","__NR_mq_open","__NR_mq_unlink","__NR_mq_timedsend","__NR_mq_timedreceive","__NR_mq_notify","__NR_mq_getsetattr","__NR_kexec_load","__NR_waitid","__NR_add_key","__NR_request_key","__NR_keyctl","__NR_ioprio_set","__NR_ioprio_get","__NR_inotify_init","__NR_inotify_add_watch","__NR_inotify_rm_watch","__NR_migrate_pages","__NR_openat","__NR_mkdirat","__NR_mknodat","__NR_fchownat","__NR_futimesat","__NR_newfstatat","__NR_unlinkat","__NR_renameat","__NR_linkat","__NR_symlinkat","__NR_readlinkat","__NR_fchmodat","__NR_faccessat","__NR_pselect6","__NR_ppoll","__NR_unshare","__NR_set_robust_list","__NR_get_robust_list","__NR_splice","__NR_tee","__NR_sync_file_range","__NR_vmsplice","__NR_move_pages","__NR_utimensat","__NR_epoll_pwait","__NR_signalfd","__NR_timerfd_create","__NR_eventfd","__NR_fallocate","__NR_timerfd_settime","__NR_timerfd_gettime","__NR_accept4","__NR_signalfd4","__NR_eventfd2","__NR_epoll_create1","__NR_dup3","__NR_pipe2","__NR_inotify_init1","__NR_preadv","__NR_pwritev","__NR_rt_tgsigqueueinfo","__NR_perf_event_open","__NR_recvmmsg","__NR_fanotify_init","__NR_fanotify_mark","__NR_prlimit64","__NR_name_to_handle_at","__NR_open_by_handle_at","__NR_clock_adjtime","__NR_syncfs","__NR_sendmmsg","__NR_setns","__NR_getcpu","__NR_process_vm_readv","__NR_process_vm_writev","__NR_kcmp","__NR_finit_module","__NR_sched_setattr","__NR_sched_getattr","__NR_renameat2","__NR_seccomp","__NR_getrandom","__NR_memfd_create","__NR_kexec_file_load","__NR_bpf","__NR_execveat","__NR_userfaultfd","__NR_membarrier","__NR_mlock2","__NR_copy_file_range","__NR_preadv2","__NR_pwritev2","__NR_pkey_mprotect","__NR_pkey_alloc","__NR_pkey_free","__NR_statx"
};


void stackOverFlowHandler(int sig)
{
    Log::instance().getError() << "stackoverflow" << endl;
    exit(MLE);
}

void setProcessReSource(int max_time, int max_memory)
{
    struct rlimit lim;

    if (max_time > 0)
    {
        lim.rlim_max = max_time / 1000 + 1; //硬限制
        lim.rlim_cur = max_time / 1000 + 1; //软限制
        if (setrlimit(RLIMIT_CPU, &lim) < 0)
        {
            Log::instance().error("setrlimit(RLIMIT_CPU) error\n");
            exit(SETRLIMIT_TIME_ERROR);
        }
    }
    if (max_memory > 0)
    {
        // 虚拟内存设置为总内存两倍
        // 两倍虚拟内存会导致java虚拟机运行出错等意外情况
        // lim.rlim_max = max_memory * 2; //硬限制
        // lim.rlim_cur = max_memory * 2; //软限制

        // if (setrlimit(RLIMIT_AS, &lim) < 0)
        // {
        //     Log::instance().error("setrlimit(RLIMIT_AS) error\n");
        //     exit(SETRLIMIT_AS_ERROR);
        // }
        lim.rlim_max = max_memory * 1024; //硬限制 
        lim.rlim_cur = max_memory * 1024; //软限制


        // 目前无法严格的把控内存不超过阈值，只能通过上面两倍虚拟内存来保证内存不过大
        if (setrlimit(RLIMIT_STACK, &lim) < 0)
        {
            Log::instance().error("setrlimit(RLIMIT_STACK) error\n");
            exit(SETRLIMIT_STACK_ERROR);
        }


        // // Log::instance().getError() << "申请信号栈" << endl;
        // stack_t ss;

        // //以下是申请信号栈，当堆栈溢出后需要用额外的信号栈来捕获SIGSEGV信号
        // ss.ss_sp = malloc(SIGSTKSZ);
        // if (ss.ss_sp == NULL)
        // {
        //     Log::instance().getError() << "malloc SIGSTKSZ fail" << endl;
        //     exit(MALLOC_ERROR);
        // }
        // ss.ss_size = SIGSTKSZ;
        // ss.ss_flags = 0;
        // if (sigaltstack(&ss, NULL) == -1)
        // {
        //     Log::instance().getError() << "sigaltstack fail" << endl;
        //     exit(SIGALTSTACK_ERROR);
        // }
        // struct sigaction sa;
        // sa.sa_handler = stackOverFlowHandler;
        // sa.sa_flags = SA_ONSTACK;

        // sigfillset(&sa.sa_mask);
        // if (sigaction(SIGSEGV, &sa, NULL) == -1)
        // {
        //     Log::instance().error("sigaction fail");
        //     exit(SIGACTION_ERROR);
        // }
    }

    //限制写入的字节不能超过OUTPUT_FILE_MAXSIZE
    lim.rlim_max = OUTPUT_FILE_MAXSIZE;
    lim.rlim_cur = OUTPUT_FILE_MAXSIZE;
    if (setrlimit(RLIMIT_FSIZE, &lim) < 0)
    {
        Log::instance().error("setrlimit(RLIMIT_FSIZE) error\n");
        exit(SETRLIMIT_FSIZE_ERROR);
    }
}

void setTimer(int max_time)
{
    // 设置为0时表示不做限制
    if(max_time <= 0)
        return;
    struct itimerval tm;
    //设定触发信号的时间，预留10ms，it_interval设置为0，只触发一次信号
    tm.it_interval.tv_sec = 0;
    tm.it_interval.tv_usec = 0;
    tm.it_value.tv_sec = max_time / 1000;
    tm.it_value.tv_usec = max_time % 1000000 + 10000;

    if (setitimer(ITIMER_VIRTUAL, &tm, NULL) < 0) //仅当进程执行时才进行计时
    {
        Log::instance().error("setitimer(VIRTUAL) error\n");
        exit(SETITIMER_ITIMER_VIRTUAL);
    }

    if (setitimer(ITIMER_PROF, &tm, NULL) < 0) 
    {
        Log::instance().error("setitimer(PROF) error\n");
        exit(SETITIMER_ITIMER_PROF);
    }

    //按实际时间计时
    //以防万一设置一个定时器，以防止各类意外情况，多一秒以防万一
    tm.it_value.tv_sec++;
    if (setitimer(ITIMER_REAL, &tm, NULL) < 0)
    {
        Log::instance().error("setitimer(REAL) error\n");
        exit(SETITIMER_ITIMER_REAL);
    }

    // settimer疑似失效，添加alarm确保正确超时
    alarm(tm.it_value.tv_sec);
}

void setNobody()
{
	struct passwd *nobody = getpwnam("nobody");
	if (nobody == NULL) {
		Log::instance().error("Cannot find user 'nobody'.");
        return;
    }
    setgid(nobody->pw_gid);
    setuid(nobody->pw_uid);
}

pid_t createProcess_(string command, int max_time, int max_memory, 
                    int enableSysCheck, ProcessSTD pstd,
                    const string& workPath, const vector<seccomp_ruler>& scmp)
{
    ProcessSTDNO pstdno = stdnoFromSTD(pstd);
    Log::instance().getOutput() << "----process pstd version----" << endl;
    return createProcess_(command, max_time, max_memory, enableSysCheck, pstdno);
}

void seccomp_add_ruler_vector(scmp_filter_ctx ctx, const vector<seccomp_ruler>& scmps) {
    for (int i = 0; i < scmps.size(); i++) {
        seccomp_rule_add_array(ctx, scmps[i].action, scmps[i].syscall, scmps[i].arg_cnt, scmps[i].args);
        Log::instance().getOutput() << "set invalid sys call: " << sysCallList[scmps[i].syscall] << ", id:" << scmps[i].syscall << endl; 
    }
}

pid_t createProcess_(string command, int max_time, int max_memory, 
                    int enableSysCheck, ProcessSTDNO pstdno, 
                    const string& workPath, const vector<seccomp_ruler>& scmps)
{
    // user等于0表示root用户
    vector<string> temps = split(command);
    if (temps.size() < 1) {
        Log::instance().getError() << "command empty" << endl;
        return -1;
    }
    char *args[temps.size() + 1];
    for (int i = 0; i < temps.size(); i++)
        args[i] = const_cast<char *>(temps[i].c_str());
    args[temps.size()] = NULL;
    Log::instance().getOutput() << command << endl;
    Log::instance().getOutput() << enableSysCheck << endl;
    Log::instance().getOutput() << pstdno.in << " " << pstdno.out << " " << pstdno.err << endl;
    pid_t t = vfork();
    if (t == 0)
    {
        if (workPath != "") {
            chdir(workPath.c_str());
        }
        Log::instance().getOutput() << "workPath:" << workPath << endl;
        Log::instance().getOutput() << "command:" << command << endl;
        // nice(19);
        setpgrp();
        closeStdno(switchStdno(pstdno));
        setProcessReSource(max_time, max_memory);
        setTimer(max_time);

        scmp_filter_ctx ctx;
        ctx = seccomp_init(SCMP_ACT_ALLOW);
        Log::instance().getOutput() << "seccomp rulers size:" << scmps.size() << endl;
        seccomp_add_ruler_vector(ctx, scmps);
        seccomp_load(ctx);
        seccomp_release(ctx);

        if (enableSysCheck & NON_SYSCHECK) {
            Log::instance().getOutput() << "set non syscall check" << endl;
        } else {
            Log::instance().getOutput() << "set syscall check" << endl;
        }
        if (!(enableSysCheck & NON_NOBODY)) {
            Log::instance().getOutput() << "set nobody" << endl;
            setNobody();
        } else {
            Log::instance().getOutput() << "set root" << endl;
        }
        if (enableSysCheck & NO_PTRACE) {
            Log::instance().getOutput() << "set no ptrace" << endl;
        } else {
            Log::instance().getOutput() << "set ptrace" << endl;
            ptrace(static_cast<__ptrace_request>(PTRACE_TRACEME), 0, NULL, NULL);
        }
        execvp(args[0], (char *const *)args);
        Log::instance().getError() << "execvp error:" << errno << endl
                                   << strerror(errno) << endl;
        cerr << "execvp error:" << errno << endl << strerror(errno) << endl;
        _exit(RE);
    }
    else if (t < 0)
    {
        Log::instance().printf("linux create process fail : %s (errno: %d)\n", strerror(errno), errno);
    }
    return t;
}

ProcessStatus commandExecuteResult(std::string command, int max_time, 
    int max_memory,int enableSysCheck, ProcessSTDNO childPstd, ProcessSTDNO parentPstd, const string& workPath, const vector<seccomp_ruler>& scmps)
{
    ProcessStatus ps;
    printTimeSpanToOutAndError();

    pid_t t = createProcess_(command, max_time, max_memory, enableSysCheck, childPstd, workPath, scmps);
    if (t < -1) {
        ps.result = SYS_ERROR;
        return ps;
    }

    // 子进程运行成功后，父进程先关闭为了传递到子进程所打开的描述符，保证管道准时发出关闭信号
    // 只关闭非标准文件符
    if (childPstd.in > 2) {
        close(childPstd.in);
    }
    if (childPstd.out > 2) {
        close(childPstd.out);
    }
    if (childPstd.err > 2) {
        close(childPstd.err);
    }

    Log::instance().getOutput() << "子进程ID:" << t << endl;
    ps = WatchProcess(t, max_time, max_memory, !(enableSysCheck & NON_SYSCHECK), parentPstd);
    // 监听进程运行成功后，关闭监听进程占用的描述符
    // 只关闭非标准文件符
    if (parentPstd.in > 2) {
        close(parentPstd.in);
    }
    if (parentPstd.out > 2) {
        close(parentPstd.out);
    }
    if (parentPstd.err > 2) {
        close(parentPstd.err);
    }
    // Log::instance().getOutput() << ps << endl;
    return ps;
}
ProcessStatus reportError(int err)
{
    ProcessStatus ps;
    ps.result = SYS_ERROR;
    ps.errorcode = err;
    ps.error = strerror(err);
    Log::instance().getError() << ps.error << endl;
    return ps;
}

ProcessStatus commandExecuteResult(string command, int max_time, int max_memory, int enableSysCheck, ProcessSTD pstd, const string& workPath, const vector<seccomp_ruler>& scmps)
{
    // 标准输出管道，标准错误管道
    int out_pipe[2] = {-1, -1}, error_pipe[2] = {-1, -1};
    // 子进程的标准描述符
    ProcessSTDNO childPstd(0, 1, 2);
    // 父进程需要读取的描述符，out表示父进程将读入子进程的输出，err则是错误输出
    ProcessSTDNO parentPstd(-1, -1, -1);
    
    Log::instance().getOutput() << pstd.in << " " << pstd.out << " " << pstd.err << endl;
    if (pstd.in != "") {
        childPstd.in = open(pstd.in.c_str(), pstd.inmod);
        if (childPstd.in < 0) {
            return reportError(errno);
        }
    }

    if (pstd.out != "") {
        childPstd.out = open(pstd.out.c_str(), pstd.outmod, 0700);
    } else {
        pipe(out_pipe);
        parentPstd.out = out_pipe[0];
        childPstd.out = out_pipe[1];
    }
    if (childPstd.out < 0) {
        return reportError(errno);
    }

    if (pstd.err != "") {
        childPstd.err = open(pstd.err.c_str(), pstd.errmod, 0700);
    } else {
        pipe(error_pipe);
        parentPstd.err = error_pipe[0];
        childPstd.err = error_pipe[1];
    }
    if (childPstd.err < 0) {
        return reportError(errno);
    }
    Log::instance().getOutput() << childPstd.in << " " << childPstd.out << " " << childPstd.err << endl
                                << parentPstd.in << " " << parentPstd.out << " " << parentPstd.err << endl;
    return commandExecuteResult(command, max_time, max_memory, enableSysCheck, childPstd, parentPstd, workPath, scmps);
}

ProcessStatus commandExecuteResult(std::string command, int max_time, 
    int max_memory,int enableSysCheck, ProcessSTDNO pstdno, const string& workPath, const vector<seccomp_ruler>& scmps)
{
    // 标准输出管道，标准错误管道
    int out_pipe[2] = {-1, -1}, error_pipe[2] = {-1, -1};
    // 子进程的标准描述符
    ProcessSTDNO childPstd;
    // 父进程需要读取的描述符，out表示父进程将读入子进程的输出，err则是错误输出
    ProcessSTDNO parentPstd(-1, -1, -1);
    Log::instance().getOutput() << "pstdno" << endl;
    Log::instance().getOutput() << pstdno.in << " " << pstdno.out << " " << pstdno.err << endl;

    // 暂时不对pstd.in做处理
    childPstd.in = pstdno.in;

    if (pstdno.out != -1) {
        childPstd.out = pstdno.out;
    } else {
        pipe(out_pipe);
        parentPstd.out = out_pipe[0];
        childPstd.out = out_pipe[1];
    }
    if (childPstd.out < 0) {
        return reportError(errno);
    }

    if (pstdno.err != -1) {
        childPstd.err = pstdno.err;
    } else {
        pipe(error_pipe);
        parentPstd.err = error_pipe[0];
        childPstd.err = error_pipe[1];
    }
    if (childPstd.err < 0) {
        return reportError(errno);
    }
    Log::instance().getOutput() << childPstd.in << " " << childPstd.out << " " << childPstd.err << endl
                                << parentPstd.in << " " << parentPstd.out << " " << parentPstd.err << endl;
    return commandExecuteResult(command, max_time, max_memory, enableSysCheck, childPstd, parentPstd, workPath, scmps);
}

inline int secToMsec(struct timeval tv)
{
    return (int)(tv.tv_usec / 1000) + tv.tv_sec * 1000;
}

int checkSysCall(const pid_t t)
{
#ifdef __x86_64__
    int id = ptrace(static_cast<__ptrace_request>(PTRACE_PEEKUSER), t, (void *)(8 * ORIG_RAX), NULL);
#else
    int id = ptrace(static_cast<__ptrace_request>(PTRACE_PEEKUSER), t, (void *)(4 * ORIG_EAX), NULL);
#endif
    id = id % 512;
    if (id == -1)
    {
        Log::instance().error("Error peeking user");
        return CONTINUE;
    }
    Log::instance().getError() << "出现了非法的系统调用(" << id << ")";
    Log::instance().getError() << sysCallList[id] << endl;
    return RE;
}

int parseStatus(int status, int pid)
{
    int result = CONTINUE;
    if (status>>8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP<<8))) {
        unsigned long event_id = 0;
        ptrace(static_cast<__ptrace_request>(PTRACE_GETEVENTMSG), pid, NULL, &event_id);
        Log::instance().getError() << "seccomp过滤系统调用(" << event_id << ")";
        Log::instance().getError() << sysCallList[event_id] << endl;
        return SYS_CHECK;
    }
    if (WIFSIGNALED(status))
    {
        int sig = WTERMSIG(status);
        switch (sig)
        {
        case SIGALRM:
        case SIGVTALRM:
        case SIGXCPU:
        case SIGKILL:
            //超时
            Log::instance().error("be killed\n");
            return TLE;
        case SIGXFSZ:
            Log::instance().error("输入输出超限\n");
            return OLE;
        case SIGSEGV:
            Log::instance().error("SIGSEGV MLE 段错误\n");
            return MLE;
        default:
            Log::instance().getError() << "捕获到意外的子进程信号(" << sig << ")" << endl;
            return RE;
        }
        return result;
    }

    if (WIFSTOPPED(status))
    {
        int sig = WSTOPSIG(status);
        switch (sig)
        {
        case SIGUSR1: //用户信号，无关紧要的
        case SIGTTIN: //用户输入信号
        case SIGTTOU: //用户输出信号
        case SIGURG:  //网络连接警告,golang编译会出现
        case SIGTRAP: //获取了被seccomp忽略的系统调用，忽略
            Log::instance().getError() << "USR/IN/OUT/UGR ... ignore(" << sig << ")" << endl;
            return CONTINUE;
        case SIGXFSZ:
            Log::instance().error("SIGXFSZ OLE \n");
            return OLE; /*输出文件大小超出限制（头文件有限制常量）*/
        case SIGVTALRM:
            Log::instance().error("SIGVTALRM TLE \n");
            return TLE; /*虚拟计时超时了*/
        case SIGXCPU:
            Log::instance().error("SIGXCPU TLE \n");
            return TLE; /*CPU计时超时了*/
        case SIGPROF:
            Log::instance().error("SIGPROF TLE \n");
            return TLE; /*用户态+内核态计时超时了*/
        case SIGALRM:
            Log::instance().error("收到定时器信号\n");
            return TLE;
        case SIGCHLD:
            // 子进程已结束
            Log::instance().error("获取到子进程结束信号 \n");
            return CONTINUE;
        case SIGSEGV:
            Log::instance().error("SIGSEGV MLE 段错误\n");
            return RE;
        default:
            Log::instance().getError() << "异常暂时信号(" << sig << ")" << endl;
            return RE;
        }
    }

    if (WIFEXITED(status)) /*表示程序已经终止了*/
    {
        int sig = WEXITSTATUS(status);
        /*表示没有任何主动信号，是正常结束的*/
        switch (sig)
        {
        case RUN_OK:
            Log::instance().error("子进程正常结束\n");
            return RUN_OK;
        case CE:
            Log::instance().error("编译或执行失败，此时子进程退出码为CE\n");
            return CE;
        case WA:
            Log::instance().error("子进程返回WA，认为程序错误\n");
            return WA;
        case TLE:
            Log::instance().error("子进程返回TLE，认为程序超时\n");
            return TLE;
        case MLE:
            Log::instance().error("子进程返回MLE，认为程序超出内存\n");
            return MLE;
        case PE:
            Log::instance().error("子进程返回PE，认为程序格式错误\n");
            return MLE;
        case OLE:
            Log::instance().error("子进程返回MLE，认为程序输出超限\n");
            return OLE;
        default:
            Log::instance().getError() << "出现意外地子进程退出码(" << sig << ")" << endl;
            return RE;
        }
    }
    return CONTINUE;
}

int exitCode(int status)
{
    if (WIFSIGNALED(status))
    {
        int sig = WTERMSIG(status);
        return sig;
    }

    if (WIFSTOPPED(status))
    {
        int sig = WSTOPSIG(status);
        return sig;
    }

    if (WIFEXITED(status)) /*表示程序已经终止了*/
    {
        int sig = WEXITSTATUS(status);
        return sig;
    }
    return 0;
}

int readFileno(string& res, int fileno, bool enableLimit = false)
{
    int len = 0;
    char buff[MAX_PIPEBUFF];
    buff[len] = '\0';
    int sum = 0;
    while (true) 
    {
        // Log::instance().getOutput() << "pre read pipe" << endl;
        len = read(fileno, buff, MAX_PIPEBUFF);
        // Log::instance().getOutput() << "post read pipe, size:" << len << endl;
        if (len <= 0) {
            break;
        }
        sum += len;
        if (res.size() > MAX_OUTLIMIT && enableLimit) {
            return -1;
        }
        if (!enableLimit && res.size() > OUTPUT_BUFF_MAXSIZE) {
            continue;
        }
        buff[len] = '\0';
        res += buff;
    }
    return sum;
}

int get_memory_by_pid(pid_t pid) {
    string filename = "/proc/" + to_string(pid) + "/status";
    ifstream status(filename);
    if (!status.is_open()) {
        Log::instance().getError() << filename << " Error:" << strerror(errno) << endl;
        return 0;
    }
    defer(
        status.close();
    );
    string s;
    while (getline(status, s)) {
        // 峰值物理内存
        if (s.find("VmHWM") == 0) {
            string temp;
            int x;
            istringstream(s) >> temp >> x;
            return x;
        }
    }
    return 0;
}

ProcessStatus WatchProcess(pid_t t, int max_time, int max_memory, bool enableSysCheck, ProcessSTDNO pstdno)
{
    int status = 0;
    ProcessStatus ps = ProcessStatus();
    struct rusage rinfo;
    Log::instance().getOutput() << "正在监控子进程:" << t << endl;
    Log::instance().getOutput() << pstdno.in << " " << pstdno.out << " " << pstdno.err << endl;
    // 统计超出MAX_OUTLIMIT的错误字节，如果output超出此大小将直接返回error
    int overflowErrorSize = 0;
    // 暂存从管道读入的字节
    char buff[MAX_PIPEBUFF];
    // 若启用了系统检查,则认为当前只检查这一个进程,若不启用则认为当前检查一整个进程组
    int pgroup = enableSysCheck ? 1 : -1;
    //为了确保数据的准确，在退出该函数前再检查一次子进程的资源
    defer(
        // options : WNOHANG 如果没有子进程exited,则立刻返回
        //           WUNTRACED 如果不是被追踪的子进程stopped,也立刻返回,如果指定的pid是被设置为追踪的子进程,则将默认启用此选项
        //           WCONTINUED (since Linux 2.6.10) 如果子进程被恢复执行,也立刻返回

        // 防止管道剩余数据,读光所有数据
        // Log::instance().getOutput() << "before exit read rest data" << endl;
        // if (pstdno.out != -1) {
        //     readFileno(ps.output, pstdno.out, true);
        // }
        // if (pstdno.err != -1) {
        //     readFileno(ps.error, pstdno.err, true);
        // }

        // 如果最后一次拿到的信号不是exited信号,则回收进程资源
        Log::instance().getError() << "defer WatchProcess" << endl;
        // 若是监听进程组,则pgroup=-1,那么等待选项使用WUNTRACED
        int wait_option = pgroup == -1 ? WUNTRACED : 0;
        // 阻塞等待子进程exited事件
        Log::instance().getError() << "defer recycle pid[" << t << "] source" << endl;
        // 直到所有监听子进程退出为止
        pid_t temp_pid;
        while ((temp_pid = wait4(t * pgroup, &status, wait_option, &rinfo)) >= 0) {
            Log::instance().getError() << "wait pid:" << temp_pid << endl;
        }

    );
    Log::instance().getOutput() << "pre set outfd, errfd as nonblock" << endl;
    // 将读入设置为非阻塞模式
    if (pstdno.out != -1) {
        int flags = fcntl(pstdno.out, F_GETFL);
        fcntl(pstdno.out, F_SETFL, flags | O_NONBLOCK);
    }
    if (pstdno.err != -1) {
        int flags = fcntl(pstdno.err, F_GETFL);
        fcntl(pstdno.err, F_SETFL, flags | O_NONBLOCK);
    }
    Log::instance().getOutput() << "set outfd, errfd as nonblock done" << endl;
    while (true) {
        // 阻塞等待子进程stopped或exited事件
        // -t表示等待以t为进程组中的进程
        // kill(-t, singal) 表示对t进程组中的每个进程都发送信号
        Log::instance().getOutput() << "wait4 event wait, t: " << t << ", pgroup: " << pgroup << endl;
        if (wait4(t * pgroup, &status, 0, &rinfo) < 0) {
            Log::instance().getOutput() << "wait4 error: " << errno << " -> " << strerror(errno)<< endl;
            Log::instance().getError() << "wait4 error" << endl;
            ps.result = SYS_ERROR;
            ps.errorcode = -1;
            return ps;
        }
        Log::instance().getOutput() << "wait4 event ready, start check" << endl;
        Log::instance().getOutput() << "pre read out and error" << endl;
        if (pstdno.out != -1) {
            if (readFileno(ps.output, pstdno.out, true) < 0) {
                ps.result = OLE;
                ps.errorcode = -1;
                kill(t * pgroup, SIGKILL);
                return ps;
            }
        }
        Log::instance().getOutput() << "read out done" << endl;
        if (pstdno.err != -1) {
            readFileno(ps.error, pstdno.err, false);
        }
        Log::instance().getOutput() << "read error done" << endl;
        int usedtime = secToMsec(rinfo.ru_utime) + secToMsec(rinfo.ru_stime);
        ps.time = max(ps.time, usedtime);

        // 此处仍存在漏洞,如当前进程有多个子进程,则rinfo.ru_maxrss得到的结果是最大的子进程占用值,而不一定是监听的进程内存
        // 在交互式判题时,如果spj与user都使用java,那么二者获取到的内存有可能取最大值
        if (enableSysCheck) {
            // 此时不允许被监控进程创建子进程
            // 读取/proc/pid/status中的VmHWM的值作为内存
            ps.memory = max(ps.memory, (int)get_memory_by_pid(t));
        } else {
            // rinfo.ru_maxrss代表的是当前进程中的子进程树中占用内存最大的值,并不能准确描述到进程号t的内存占用
            // 并且拿到的是虚拟内存,比物理内存虚高一些
            // 用于java等需要虚拟机无法限制创建子进程的语言
            ps.memory = max(ps.memory, (int)rinfo.ru_maxrss);
        }

        if (max_time > 0 && ps.time > max_time)
        {
            Log::instance().getError() << "时间检查已超时" << "额定:" << max_time << "实际:" << ps.time << ",单位:ms" << endl;
            ps.result = TLE;
            ps.errorcode = -1;
            kill(t * pgroup, SIGKILL);
            return ps;
        }
        if (max_memory > 0 && ps.memory > max_memory)
        {
            Log::instance().getError() << "内存检查已超出," << "额定:" << max_memory << "实际:" << ps.memory << ",单位:KB" << endl;
            ps.result = MLE;
            ps.errorcode = -1;
            kill(t * pgroup, SIGKILL);
            return ps;
        }
        ps.errorcode = exitCode(status);
        //正在等待信号分析
        int st = parseStatus(status, t);
        //检查系统调用
        if (st == SYS_CHECK && enableSysCheck)
        {
            st = checkSysCall(t);
        }
        if (st != CONTINUE && st != SYS_CHECK)
        {
            Log::instance().getError() << "出现非CONTINUE和SYS_CHECK返回值:" << st << endl;
            ps.result = st;
            kill(t * pgroup, SIGKILL);
            return ps;
        }
        //继续执行子进程
        if (ptrace(static_cast<__ptrace_request>(PTRACE_SETOPTIONS), t, NULL, PTRACE_O_TRACESECCOMP) < 0) {
            Log::instance().getError() << "Error set child traceseccomp: " << t 
                << ", errno: " << errno 
                << ", error: " << strerror(errno) << endl;
            kill(t * pgroup, SIGKILL);
            ps.result = RE;
            ps.errorcode = -1;
            return ps;

        }
        if (ptrace(static_cast<__ptrace_request>(PTRACE_CONT), t, NULL, NULL) < 0) {
            Log::instance().getError() << "Error ptracsing child: " << t 
                << ", errno: " << errno 
                << ", error: " << strerror(errno) << endl;
            kill(t * pgroup, SIGKILL);
            ps.result = RE;
            ps.errorcode = -1;
            return ps;
        }
    }
    return ps;
}

#endif

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <locale.h>
#include "Psapi.h"


PROCESS_INFORMATION createProcess_(std::string command)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));
    char *cd = const_cast<char *>(command.c_str());
    Log::instance().getOutput() << "creating process" << endl;
    Log::instance().getOutput() << "comand:" << command << endl;
    if (!CreateProcessA(NULL,                                    // No module name (use command line)
                        cd,                                      // Command line
                        NULL,                                    // Process handle not inheritable
                        NULL,                                    // Thread handle not inheritable
                        FALSE,                                   // Set handle inheritance to FALSE
                        DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS, // 仅有当前进程调试的进程
                        NULL,                                    // Use parent's environment block
                        NULL,                                    // Use parent's starting directory
                        (LPSTARTUPINFOA)&si,                     // Pointer to STARTUPINFO structure
                        &pi)                                     // Pointer to PROCESS_INFORMATION structure
    )
    {
        Log::instance().getError() << "CreateProcess failed (" << GetLastError() << ").\n";
    }

    // Close process and thread handles.
    // CloseHandle( pi.hProcess );
    // CloseHandle( pi.hThread );
    return pi;
}

void freeHandle(PROCESS_INFORMATION pi)
{
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

int parse_event(PROCESS_INFORMATION pi, DEBUG_EVENT de)
{
    /*
    #define EXCEPTION_DEBUG_EVENT					       1
    #define CREATE_THREAD_DEBUG_EVENT				       2
    #define CREATE_PROCESS_DEBUG_EVENT				       3
    #define EXIT_THREAD_DEBUG_EVENT 				       4
    #define EXIT_PROCESS_DEBUG_EVENT				       5
    #define LOAD_DLL_DEBUG_EVENT					       6
    #define UNLOAD_DLL_DEBUG_EVENT					       7
    #define OUTPUT_DEBUG_STRING_EVENT				       8
    #define RIP_EVENT						       9
    */
    CHAR DllName[MAX_PATH] = {'\0'}; // 存储DLL的缓冲区
    SIZE_T nNumberOfBytesRead = 0;   // 读取的字节数
    DWORD dwAddrImageName = 0;
    switch (de.dwDebugEventCode)
    {
    case CREATE_PROCESS_DEBUG_EVENT:
        Log::instance().printf("create process\n");
        break;

    case CREATE_THREAD_DEBUG_EVENT:
        Log::instance().printf("create thread\n");
        break;

    case EXCEPTION_DEBUG_EVENT:
        switch (de.u.Exception.ExceptionRecord.ExceptionCode)
        {
        case EXCEPTION_INT_DIVIDE_BY_ZERO:
            Log::instance().printf("zero\n");
            return RE;
        case EXCEPTION_INT_OVERFLOW:
            Log::instance().printf("INT\n");
            return RE;
        case EXCEPTION_ACCESS_VIOLATION:
            Log::instance().printf("ACCESS\n");
            return RE;
        case EXCEPTION_DATATYPE_MISALIGNMENT:
            Log::instance().printf("DATATYPE\n");
            return RE;
        case EXCEPTION_FLT_STACK_CHECK:
            Log::instance().printf("DATATYPE\n");
            return RE;
        case EXCEPTION_INVALID_DISPOSITION:
            Log::instance().printf("DISPOSITION\n");
            return RE;
        case EXCEPTION_STACK_OVERFLOW:
            Log::instance().printf("OVERFLOW\n");
            return RE;
        case EXCEPTION_BREAKPOINT:
            Log::instance().printf("break point\n");
            break;
        default:
            Log::instance().printf("unkown exception(0x%X)\n", de.u.Exception.ExceptionRecord.ExceptionCode);
            return SYS_ERROR;
            break;
        }
        break;

    case EXIT_PROCESS_DEBUG_EVENT:
        Log::instance().printf("exit process\n");
        return RUN_OK;
        break;
    case EXIT_THREAD_DEBUG_EVENT:
        Log::instance().printf("exit thread\n");
        break;
    case UNLOAD_DLL_DEBUG_EVENT:
        Log::instance().printf("unload dll\n");
        break;
    case LOAD_DLL_DEBUG_EVENT:
        ReadProcessMemory(pi.hProcess, de.u.LoadDll.lpImageName, &dwAddrImageName, sizeof(dwAddrImageName), &nNumberOfBytesRead);
        ReadProcessMemory(pi.hProcess, (void *)dwAddrImageName, DllName, sizeof(DllName), &nNumberOfBytesRead);
        if (de.u.LoadDll.fUnicode)
        {
            Log::instance().wprintf(L"DLLNAME: %s\n", DllName);
        }
        else
        {
            Log::instance().printf("DLLNAME: %s\n", DllName);
        }
        // Log::instance().printf("load dll\n");
        break;
    case RIP_EVENT:
        Log::instance().printf("RIP_EVENT\n");
        return SYS_ERROR;
    case OUTPUT_DEBUG_STRING_EVENT:
        Log::instance().printf("output string\n");
        Log::instance().getOutput() << "OUTPUT_DEBUG_STRING_EVENT: " << de.u.DebugString.fUnicode << endl;
        break;
    default:
        Log::instance().printf("other event:%d\n", de.dwDebugEventCode);
        break;
    }
    return CONTINUE;
}

ProcessStatus commandExecuteResult(string command, int max_time, int max_memory, int enableSysCheck, ProcessSTD pstd)
{
    ProcessStatus ps;
    PROCESS_INFORMATION pi = createProcess_(command);
    Log::instance().getOutput() << "PROCESS_INFORMATION" << endl;
    Log::instance().getOutput() << pi.hProcess << " " << pi.hThread << endl;
    if (pi.hProcess == 0) //进程创建失败时
    {
        ps.result = SYS_ERROR;
        return ps;
    }
    Log::instance().getOutput() << "watching process" << endl;
    ps = WatchProcess(pi, max_time, max_memory, enableSysCheck);
    return ps;
}

/*
监控进程
:@params pi: 要监控的进程信息
:@params max_time: 最长等待时间(为0则不限制时间)
:@params max_memory: 最大占用内存(为0则不限制内存)
*/
ProcessStatus WatchProcess(PROCESS_INFORMATION pi, int max_time, int max_memory, bool enableSysCheck)
{
    // Log::instance().getOutput() << "正在判题" << endl;
    HANDLE handle = pi.hProcess;
    DWORD res;
    PROCESS_MEMORY_COUNTERS pmc = {sizeof(pmc)};
    ProcessStatus ps = ProcessStatus();
    FILETIME ftCreation, ftExit, ftKernel, ftUser;
    SYSTEM_INFO sysInfo;
    SYSTEMTIME stKernel, stUser;
    GetSystemInfo(&sysInfo);
    DEBUG_EVENT de;
    int flag;
    while (true) //若程序仍然在运行
    {
        flag = WaitForDebugEvent(&de, INFINITE);
        if (flag == 0)
        {
            Log::instance().printf("WaitForDebugEvent error:%d\n", GetLastError());
            ps.result = SYS_ERROR;
            break;
        }
        GetProcessTimes(pi.hProcess, &ftCreation, &ftExit, &ftKernel, &ftUser);
        GetProcessMemoryInfo(pi.hProcess, &pmc, sizeof(pmc));
        FileTimeToSystemTime(&ftKernel, &stKernel);
        FileTimeToSystemTime(&ftUser, &stUser);
        DWORD used_time = (stKernel.wMilliseconds + stUser.wMilliseconds) / sysInfo.dwNumberOfProcessors;
        ps.time = max(ps.time, (int)used_time);
        ps.memory = max(ps.memory, (int)pmc.PeakWorkingSetSize);
        if (max_time > 0 && ps.time > max_time)
        {
            ps.result = TLE;
            TerminateProcess(handle, TLE);
            break;
        }
        if (max_memory > 0 && ps.memory > max_memory)
        {
            ps.result = MLE;
            TerminateProcess(handle, MLE);
            break;
        }
        int status = parse_event(pi, de);
        // Log::instance().getOutput() << "status:" << status << " " << codeToStr[status] << endl;
        if (status != CONTINUE)
        {
            ps.result = status;
            if (status != RUN_OK)
                TerminateProcess(handle, status);
            break;
        }
        flag = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
        if (flag == 0)
        {
            Log::instance().getOutput() << "continue debug process fail:" << GetLastError() << endl;
            ps.result = SYS_ERROR;
            break;
        }
    }
    DWORD exitcode;
    flag = GetExitCodeProcess(pi.hProcess, &exitcode);
    if (flag == 0)
    {
        Log::instance().getOutput() << "GetExitCodeProcess fail:" << GetLastError() << endl;
    }
    else if (ps.result == RUN_OK) //额外检查完成任务的情况
    {
        Log::instance().getOutput() << "exitcode:" << exitcode << endl;
        if (exitcode != 0)
        {
            ps.result = RUN_FAIL;
        }
    }
    Log::instance().getOutput() << "debug process exit" << endl;
    freeHandle(pi);
    return ps;
}

#endif